#include "gamecontrol.h"
#include "playhand.h"
#include "datamanager.h"
#include <QRandomGenerator>
#include <QTimer>

GameControl::GameControl(QObject *parent) : QObject{parent}
{

}

// 初始化玩家
void GameControl::playerInit()
{
    // 对象的实例化
    m_robotLeft = new Robot("机器人A", this);
    m_robotRight = new Robot("机器人B", this);
    m_user = new UserPlayer("自己", this);

    // 头像显示
    m_robotLeft->setDirection(Player::Left);
    m_robotRight->setDirection(Player::Right);
    m_user->setDirection(Player::Right);

    // 随机产生性别
    Player::Sex sex;
    sex = static_cast<Player::Sex>(QRandomGenerator::global()->bounded(2));
    m_robotLeft->setSex(sex);
    sex = static_cast<Player::Sex>(QRandomGenerator::global()->bounded(2));
    m_robotRight->setSex(sex);
    sex = static_cast<Player::Sex>(QRandomGenerator::global()->bounded(2));
    m_user->setSex(sex);

    // 出牌顺序
    m_user->setPrePlayer(m_robotLeft);
    m_user->setNextPlayer(m_robotRight);

    m_robotLeft->setPrePlayer(m_robotRight);
    m_robotLeft->setNextPlayer(m_user);

    m_robotRight->setPrePlayer(m_user);
    m_robotRight->setNextPlayer(m_robotLeft);

    // 指定当前玩家
    // m_curPlayer = m_user;

    // 处理玩家发射出的下注信号
    connect(m_user, &UserPlayer::notifyGrabLordBet, this, &GameControl::onGrabet);
    connect(m_robotLeft, &UserPlayer::notifyGrabLordBet, this, &GameControl::onGrabet);
    connect(m_robotRight, &UserPlayer::notifyGrabLordBet, this, &GameControl::onGrabet);

    // 传递出牌玩家对象和打出去的牌
    connect(this, &GameControl::pendingInfo, m_robotLeft, &Robot::storePendingInfo);
    connect(this, &GameControl::pendingInfo, m_robotRight, &Robot::storePendingInfo);
    connect(this, &GameControl::pendingInfo, m_user, &Robot::storePendingInfo);

    // 处理玩家出牌
    connect(m_robotLeft, &Robot::notifyPlayHand, this, &GameControl::onPlayHand);
    connect(m_robotRight, &Robot::notifyPlayHand, this, &GameControl::onPlayHand);
    connect(m_user, &Robot::notifyPlayHand, this, &GameControl::onPlayHand);


}

// 得到玩家的实例对象
Robot *GameControl::getLeftRobot() const
{
    return m_robotLeft;
}

// 得到玩家的实例对象
Robot *GameControl::getRightRobot() const
{
    return m_robotRight;
}

// 得到玩家的实例对象
UserPlayer *GameControl::getUserPlayer() const
{
    return m_user;
}

// 设置当前玩家
void GameControl::setCurrentPlayer(Player *player)
{
    m_curPlayer = player;
}

// 根据次序来设置玩家
void GameControl::setCurrentPlayer(int index)
{
    if (index == 1) {
        m_curPlayer = m_user;
    } else if (index == 2) {
        m_curPlayer = m_robotLeft;
    } else if (index == 3) {
        m_curPlayer = m_robotRight;
    }
}

// 获取当前玩家
Player *GameControl::getCurrentPlayer() const
{
    return m_curPlayer;
}

// 得到已出牌玩家
Player *GameControl::getPendPlayer() const
{
    return m_pendPlayer;
}

// 得到当前轮次所出的扑克牌
Cards GameControl::getPendCards() const
{
    return m_pendCards;
}

// 初始化扑克牌
void GameControl::initAllCards()
{
    if (DataManager::getInstance()->isNetworkMode()) {
        m_allCards = DataManager::getInstance()->getCards();
        m_allCards.add(DataManager::getInstance()->getLast3Cards());
        return;
    }

    m_allCards.clear();
    // 初始化所有的52张扑克牌
    for (int p = Card::Card_Begin + 1; p < Card::Card_SJ; ++ p) {
        for (int s = Card::Suit_Begin + 1; s < Card::Suit_End; ++ s) {
            Card c(static_cast<Card::CardPoint>(p), static_cast<Card::CardSuit>(s));
            m_allCards.add(c);
        }
    }
    // 初始化大小王
    m_allCards.add(Card(Card::Card_SJ, Card::Suit_Begin));
    m_allCards.add(Card(Card::Card_BJ, Card::Suit_Begin));
}

// 每次发一张牌
Card GameControl::takeOneCard()
{
    return m_allCards.takeRandomCard();
}

Cards GameControl::getSurplusCards() const
{
    return m_allCards;  // 发得只剩下最后三张扑克牌了，直接返回m_allCards即可
}

void GameControl::resetCardsData()
{
    // 洗牌
    initAllCards();
    // 清空所有玩家的手牌
    m_robotLeft->clearCards();
    m_robotRight->clearCards();
    m_user->clearCards();
    // 初始化出牌玩家和手牌
    m_pendPlayer = nullptr;
    m_pendCards.clear();

}

// 准备叫地主
void GameControl::startLordCard()
{
    m_curPlayer->prepareCallLord();
    emit playerStatusChanged(m_curPlayer, ThinkingForCallLord);
}

// 成为地主
void GameControl::becomeLord(Player *player, int bet)
{
    m_curBet = bet;
    player->setRole(Player::Lord);
    player->getPrePlayer()->setRole(Player::Farmer);
    player->getNextPlayer()->setRole(Player::Farmer);

    m_curPlayer = player;
    player->storeDispatchCards(m_allCards);

    QTimer::singleShot(2000, this, [=]()
    {
        emit gameStatusChanged(PlayingHand);
        emit playerStatusChanged(player, ThinkingForPlayHand);
        m_curPlayer->preparePlayHand();
    });
}

// 清空所有玩家的得分
void GameControl::clearPlayerScore()
{
    m_robotLeft->setScore(0);
    m_robotRight->setScore(0);
    m_user->setScore(0);
}

// 得到玩家下注的最高分数
int GameControl::getPlayerMaxBet() const
{
    return m_betRecord.bet;
}

// 处理叫地主的信号
void GameControl::onGrabet(Player *player, int bet)
{
    // 1. 通知主界面玩家叫地主（更新信息提示）
    // 当bet == 0 表示当前玩家已经放弃叫地主，如果m_betRecord.bet >= bet， 则表示当前玩家未抢到地主
    if (bet == 0 || m_betRecord.bet >= bet) {
        emit notifyPlayerGrabLordBet(player, 0, false);
    } else if (bet > 0 && m_betRecord.bet == 0) {
        // 第一个抢地主的玩家
        emit notifyPlayerGrabLordBet(player, bet, true); //
    } else {
        // 第2，3个抢地主的玩家
        emit notifyPlayerGrabLordBet(player, bet, false);
    }


    // 2. 判断玩家下注是不是3分，如果是，则当前玩家直接成为地主，抢地主结束
    if (bet == 3) {
        // 玩家成为地主
        becomeLord(player, bet);
        // 清空数据
        m_betRecord.reset();
        return ;
    }
    // 3. 下注不够3分，对玩家的分数进行比较，分数高的是地主
    if (m_betRecord.bet < bet) {
        m_betRecord.bet = bet;
        m_betRecord.player = player;
    }
    ++ m_betRecord.times;
    // 如果每个玩家都抢过一次地主，则这一轮次的抢地主阶段结束
    if (m_betRecord.times == 3) {
        if (m_betRecord.bet == 0) {
            emit gameStatusChanged(DispatchCard);
        } else {
            becomeLord(m_betRecord.player, m_betRecord.bet);
        }
        m_betRecord.reset();
        return ;
    }
    // 4. 切换玩家，通知下一个玩家继续抢地主
    m_curPlayer = player->getNextPlayer();
    // 发送信号给主界面，告知当前状态为抢地主状态
    emit playerStatusChanged(m_curPlayer, ThinkingForCallLord);
    m_curPlayer->prepareCallLord();
}

// 处理出牌
void GameControl::onPlayHand(Player *player, const Cards &cards)
{
    // 1. 将玩家出牌的信号转发给主界面
    emit notifyPlayHand(player, cards);

    // 2. 如果玩家所出牌不是空牌，给其它玩家发送信号，保存出牌玩家对象打出的牌
    if (!cards.isEmpty()) {
        m_pendPlayer = player;
        m_pendCards = cards;
        emit pendingInfo(player, cards);
    }

    //  如果有炸弹，则底分翻倍
    Cards myCards = const_cast<Cards&>(cards);
    PlayHand::HandType type = PlayHand(myCards).getHandType();
    if (type == PlayHand::Hand_Bomb || type == PlayHand::Hand_Bomb_Jokers) {
        m_curBet = m_curBet * 2; // TODO : ??????
    }

    // 3. 如果玩家的牌全部出完了，就结算本局玩家游戏的总分
    if (player->getCards().isEmpty()) {
        Player* pre = player->getPrePlayer();
        Player* next = player->getNextPlayer();
        // 此局，当前玩家是地主，并且已近出完牌了，获得本局游戏的胜利
        if (player->getRole() == Player::Lord) {
            player->setScore(player->getScore() + 2 * m_curBet);
            pre->setScore(pre->getScore() - m_curBet);
            next->setScore(next->getScore() - m_curBet);
            // 改变玩家的状态
            player->setWin(true);
            pre->setWin(false);
            next->setWin(false);
        }
        // 此局，当前玩家是农民，并且已近出完牌了，获得本局游戏的胜利
        else {
            player->setWin(true);
            player->setScore(player->getScore() + m_curBet);
            if (pre->getRole() == Player::Lord) {
                pre->setScore(pre->getScore() - 2 * m_curBet);
                next->setScore(next->getScore() +  m_curBet);
                pre->setWin(false);
                next->setWin(true);
            } else {
                    next->setScore(next->getScore() - 2 * m_curBet);
                    pre->setScore(pre->getScore() +  m_curBet);
                    next->setWin(false);
                    pre->setWin(true);
            }
        }
        emit playerStatusChanged(player, GameControl::Winning); // 发射玩家状态变化的信号 此局游戏结束
        return;
    }

    // 4， 如果玩家的牌未出完，则下一个玩家继续出牌
    m_curPlayer = player->getNextPlayer();
    m_curPlayer->preparePlayHand();
    emit playerStatusChanged(m_curPlayer, GameControl::ThinkingForPlayHand); // 发射玩家状态变化的信号 继续出牌
}
